#include "StdAfx.h"
#include "ShaderManager.h"
#include "Shader.h"
#include "ShaderProgram.h"

namespace rkt
{
	IShaderManager*	ShaderManager::Instance()
	{
		static ShaderManager sm;
		return &sm;
	}

	IShader*	ShaderManager::createShaderFromFile(ShaderType st,const std::string& fn)
	{
		m_mutex.Lock();
		IShader *pShader = 0;
		if(names.find(fn) != names.end()) 
		{
			pShader = names[fn];
			items[pShader]->addRef();
		}
		else
		{
			rkt::CStreamHelper pStream = rkt::getFileSystem()->open(fn.c_str());
			if(pStream)
			{
				uint len = pStream->getLength();
				uchar *pData = new uchar[len];
				pStream->read(pData,len);
				pShader = _createShaderFromMemory(st,pData,len,fn);
				if(pShader)
				{
					do_add(fn,pShader,static_cast<Shader*>(pShader));
				}
				delete[] pData;
			}
		}

		m_mutex.Unlock();
		return pShader;
	}

	IShader*	ShaderManager::createShaderFromMemory(ShaderType st,const uchar *pBuffer,uint len,const char* name)
	{
		m_mutex.Lock();

		std::string str;
		if(name)
			str = name;
		else
			str = getUniqueString();
		IShader *pShader = _createShaderFromMemory(st,pBuffer,len,str);
		if(pShader)
		{
			do_add(str,pShader,static_cast<Shader*>(pShader));
		}
		m_mutex.Unlock();

		return pShader;
	}

	void			ShaderManager::releaseShader(IShader* pShader)
	{
		m_mutex.Lock();
		del(pShader);
		m_mutex.Unlock();
	}

	void			ShaderManager::releaseAll()
	{
		m_mutex.Lock();
		std::map<IShader*,ManagedItem*>::iterator e = items.end();
		for(std::map<IShader*,ManagedItem*>::iterator b = items.begin();b != e;++b)
		{
			doDelete((*b).first);
			delete (*b).second;
		}
		items.clear();
		names.clear();
		m_mutex.Unlock();
	}

	const char* ShaderManager::getUniqueString()
	{
		m_mutex.Lock();
		static char szName[256];
		/*do
		{
			str.format("ReShaderManagerUnique%d",m_ui32Num++);
		}
		while(names.find(str) != names.end());*/
		
		sprintf_s(szName,"ReShaderManagerUnique%d",m_ui32Num++);

		m_mutex.Unlock();
		return szName;
	}

	GLenum getGLShaderType(ShaderType st)
	{
#if RENDER_SYSTEM == RENDER_SYSTEM_GLES2
		assert(0);
		return 0;
#else
		switch(st)
		{
		case ST_VERTEX_PROGRAM:
			return GL_VERTEX_PROGRAM_ARB;
		case ST_FRAGMENT_PROGRAM:
			return GL_FRAGMENT_PROGRAM_ARB;
		}
		return GL_VERTEX_PROGRAM_ARB;
#endif
	}
	
	IShaderProgram*	ShaderManager::createShaderProgram(const char* name)
	{
		std::string str;
		if(name)
			str = name;
		else
			str = getUniqueString();
		return new ShaderProgram(str);
	}

	IShader*	ShaderManager::_createShaderFromMemory(ShaderType st,const uchar* pBuffer,uint len,const std::string& name)
	{
		Shader *pShader = new Shader(name);
		if(pShader)
		{
			if(!pShader->create(st,pBuffer,len))
			{
				delete pShader;
				pShader = 0;
			}
		}

		return pShader;
	}

	void ShaderManager::doDelete(IShader* pShader)
	{
		if(pShader)
		{
			GLuint id = static_cast<Shader*>(pShader)->getGLShaderID();
#if RENDER_SYSTEM == RENDER_SYSTEM_GLES2
			assert(0);
#else
			glDeleteProgramsARB(1,&id);
#endif
			delete static_cast<Shader*>(pShader);
		}
	}

}